/*
 * Copyright (C) 2008 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.sdk.files;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.StringReader;
import java.util.ArrayList;
import java.util.List;

import android.content.Context;
import android.content.Intent;
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.PaintFlagsDrawFilter;
import android.graphics.PixelFormat;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.PaintDrawable;
import android.net.Uri;
import android.os.IBinder;
import android.util.Log;
import android.webkit.MimeTypeMap;
import android.widget.Toast;

import com.sdk.bitmap.FastBitmapDrawable;

/**
 * Various utilities shared amongst the Launcher's classes.
 */
public final class FileUtilities {
	private static int sIconWidth = -1;
	private static int sIconHeight = -1;

	private static final Paint sPaint = new Paint();
	private static final Rect sBounds = new Rect();
	private static final Rect sOldBounds = new Rect();
	private static Canvas sCanvas = new Canvas();
	static final int KILL_PIDS_FOR_MEMORY_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 79;
	static {
		sCanvas.setDrawFilter(new PaintFlagsDrawFilter(Paint.DITHER_FLAG,
				Paint.FILTER_BITMAP_FLAG));
	}

	/**
	 * Returns a Drawable representing the thumbnail of the specified Drawable.
	 * The size of the thumbnail is defined by the dimension
	 * android.R.dimen.launcher_application_icon_size.
	 * 
	 * This method is not thread-safe and should be invoked on the UI thread
	 * only.
	 * 
	 * @param icon
	 *            The icon to get a thumbnail of.
	 * @param context
	 *            The application's context.
	 * 
	 * @return A thumbnail for the specified icon or the icon itself if the
	 *         thumbnail could not be created.
	 */
	public static Drawable createIconThumbnail(Drawable icon, Context context) {
		if (sIconWidth == -1) {
			final Resources resources = context.getResources();
			sIconWidth = sIconHeight = (int) resources
					.getDimension(android.R.dimen.app_icon_size);
		}

		int width = sIconWidth;
		int height = sIconHeight;

		final int iconWidth = icon.getIntrinsicWidth();
		final int iconHeight = icon.getIntrinsicHeight();

		if (icon instanceof PaintDrawable) {
			final PaintDrawable painter = (PaintDrawable) icon;
			painter.setIntrinsicWidth(width);
			painter.setIntrinsicHeight(height);
		}

		if (width > 0 && height > 0) {
			if (width < iconWidth || height < iconHeight) {
				final float ratio = (float) iconWidth / iconHeight;

				if (iconWidth > iconHeight) {
					height = (int) (width / ratio);
				} else if (iconHeight > iconWidth) {
					width = (int) (height * ratio);
				}

				final Bitmap.Config c = icon.getOpacity() != PixelFormat.OPAQUE ? Bitmap.Config.ARGB_8888
						: Bitmap.Config.RGB_565;
				final Bitmap thumb = Bitmap.createBitmap(sIconWidth,
						sIconHeight, c);
				final Canvas canvas = sCanvas;
				canvas.setBitmap(thumb);
				// Copy the old bounds to restore them later
				// If we were to do oldBounds = icon.getBounds(),
				// the call to setBounds() that follows would
				// change the same instance and we would lose the
				// old bounds
				sOldBounds.set(icon.getBounds());
				final int x = (sIconWidth - width) / 2;
				final int y = (sIconHeight - height) / 2;
				icon.setBounds(x, y, x + width, y + height);
				icon.draw(canvas);
				icon.setBounds(sOldBounds);
				icon = new FastBitmapDrawable(thumb);
			} else if (iconWidth < width && iconHeight < height) {
				final Bitmap.Config c = Bitmap.Config.ARGB_8888;
				final Bitmap thumb = Bitmap.createBitmap(sIconWidth,
						sIconHeight, c);
				final Canvas canvas = sCanvas;
				canvas.setBitmap(thumb);
				sOldBounds.set(icon.getBounds());
				final int x = (width - iconWidth) / 2;
				final int y = (height - iconHeight) / 2;
				icon.setBounds(x, y, x + iconWidth, y + iconHeight);
				icon.draw(canvas);
				icon.setBounds(sOldBounds);
				icon = new FastBitmapDrawable(thumb);
			}
		}

		return icon;
	}

	/**
	 * Returns a Bitmap representing the thumbnail of the specified Bitmap. The
	 * size of the thumbnail is defined by the dimension
	 * android.R.dimen.launcher_application_icon_size.
	 * 
	 * This method is not thread-safe and should be invoked on the UI thread
	 * only.
	 * 
	 * @param bitmap
	 *            The bitmap to get a thumbnail of.
	 * @param context
	 *            The application's context.
	 * 
	 * @return A thumbnail for the specified bitmap or the bitmap itself if the
	 *         thumbnail could not be created.
	 */
	static Bitmap createBitmapThumbnail(Bitmap bitmap, Context context) {
		if (sIconWidth == -1) {
			final Resources resources = context.getResources();
			sIconWidth = sIconHeight = (int) resources
					.getDimension(android.R.dimen.app_icon_size);
		}

		int width = sIconWidth;
		int height = sIconHeight;

		final int bitmapWidth = bitmap.getWidth();
		final int bitmapHeight = bitmap.getHeight();

		if (width > 0 && height > 0
				&& (width < bitmapWidth || height < bitmapHeight)) {
			final float ratio = (float) bitmapWidth / bitmapHeight;

			if (bitmapWidth > bitmapHeight) {
				height = (int) (width / ratio);
			} else if (bitmapHeight > bitmapWidth) {
				width = (int) (height * ratio);
			}

			final Bitmap.Config c = (width == sIconWidth && height == sIconHeight) ? bitmap
					.getConfig() : Bitmap.Config.ARGB_8888;
			final Bitmap thumb = Bitmap
					.createBitmap(sIconWidth, sIconHeight, c);
			final Canvas canvas = sCanvas;
			final Paint paint = sPaint;
			canvas.setBitmap(thumb);
			paint.setDither(false);
			paint.setFilterBitmap(true);
			sBounds.set((sIconWidth - width) / 2, (sIconHeight - height) / 2,
					width, height);
			sOldBounds.set(0, 0, bitmapWidth, bitmapHeight);
			canvas.drawBitmap(bitmap, sOldBounds, sBounds, paint);
			return thumb;
		}

		return bitmap;
	}

	/**
	 * 格式化容量
	 * 
	 * @param size
	 * @return
	 */
	public static String formateSize(long size) {
		if (size < (1 << 10)) {
			return size + "B";
		} else if (size < (1 << 20)) {
			return (size >> 10) + "KB";
		} else if (size < (1 << 30)) {
			return (size >> 20) + "MB";
		} else if (size < (1 << 40)) {
			return (size >> 30) + "GB";
		} else {
			return (size >> 40) + "TB";
		}
	}

	public static String getAllCpuUsage(String cache) {
		try {
			BufferedReader br = null;
			if (cache == null) {
				final String cmd = "top -n 1";
				Process process;
				final Runtime runtime = Runtime.getRuntime();
				process = runtime.exec(cmd);
				final InputStream is = process.getInputStream();
				final InputStreamReader isr = new InputStreamReader(is);
				br = new BufferedReader(isr);
			} else {
				final StringReader sr = new StringReader(cache);
				br = new BufferedReader(sr);
			}

			String line;
			while ((line = br.readLine()) != null) {
				if (line.length() > 0) {
					return line;
				}
			}
		} catch (final Exception e) {
			e.fillInStackTrace();
			Log.e("Process Manager", "Unable to execute top command");
		}
		return "";
	}

	public static String getFileExtension(File file) {
		if (file == null || file.isDirectory()) {
			return "";
		} else {
			final int index = file.getName().lastIndexOf(".");
			String ext = "";
			if (index != -1) {
				ext = file.getName().substring(index);
			}
			return ext;
		}
	}

	/**
	 * 尝试调用系统安装的软件打开文件
	 * @param context 上下文
	 * @param file 要打开的文件
	 */
	public static void tryOpenFile(Context context, File file) {
		final String type = getMimeType(file);
		if (type != null) {
			try {
				final Uri uri = Uri.parse("file://" + file.getPath());
				final Intent intent = new Intent(Intent.ACTION_VIEW);
				intent.setDataAndType(uri, type);
				intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
				context.startActivity(intent);
			} catch (final Exception e) {
				// TODO: handle exception
			}
		} else {
			Toast.makeText(context, "Sorry, can't find a program to open it. ",
					Toast.LENGTH_SHORT).show();
		}
	}

	public static String getMimeType(File file) {
		final String ext = getFileExtension(file);

		String type = null;
		// if(ext.equalsIgnoreCase(".apk")){
		// type = "application/vnd.android.package-archive";
		// }
		// else if (ext.equalsIgnoreCase(".jpg")||
		// ext.equalsIgnoreCase(".gif") ||
		// ext.equalsIgnoreCase(".png") ||
		// ext.equalsIgnoreCase(".bmp")) {
		// type = "vnd.android.cursor.dir/image";
		// }
		// else if (ext.equalsIgnoreCase(".mp3")||
		// ext.equalsIgnoreCase(".ogg") ||
		// ext.equalsIgnoreCase(".wav") ||
		// ext.equalsIgnoreCase(".3gp") ||
		// ext.equalsIgnoreCase(".mp4")) {
		// type = "vnd.android.cursor.dir/video";
		// }
		if (ext.equalsIgnoreCase(".txt") || ext.equalsIgnoreCase(".htm")
				|| ext.equalsIgnoreCase(".html")) {
			type = "text/plain";
		} else {
			type = MimeTypeMap.getSingleton().getMimeTypeFromExtension(
					ext.replace(".", ""));
		}
		return type;
	}

	// 拷贝文件
	private static void copyFile(File source, File dest) throws Exception {
		final File in = source;
		final File out = dest;
		final FileInputStream inFile = new FileInputStream(in);
		final FileOutputStream outFile = new FileOutputStream(out);
		final byte[] buffer = new byte[1024];
		int i = 0;
		while ((i = inFile.read(buffer)) != -1) {
			outFile.write(buffer, 0, i);
		}// end while
		inFile.close();
		outFile.close();
	}// end copyFile

	// 处理目录
	private static void copyDir(File source, File dest) throws Exception {
		File source1;
		File dest1;

		final File[] file = source.listFiles();
		for (int i = 0; i < file.length; i++)
			if (file[i].isFile()) {
				source1 = file[i];
				dest1 = new File(dest, file[i].getName());
				copyFile(source1, dest1);
			}// end if
		for (int i = 0; i < file.length; i++)
			if (file[i].isDirectory()) {
				source1 = file[i];
				dest1 = new File(dest, file[i].getName());
				dest1.mkdir();
				copyDir(source1, dest1);
			}// end if
	}// end copyDict

	/**
	 * 删除文件夹
	 * @param file 要删除的文件夹
	 * @throws Exception 
	 */
	private static void deleteDir(File file) throws Exception {
		final File[] files = file.listFiles();
		for (int i = 0; i < files.length; i++) {
			if (files[i].isFile()) {
				deleteFile(files[i]);
			}// end if
		}
		for (int i = 0; i < files.length; i++) {
			if (files[i].isDirectory()) {
				deleteDir(files[i]);
			}// end if
		}
		file.delete();
	}

	private static void deleteFile(File file) throws Exception {
		if (!file.delete()) {
			throw new Exception();
		}
	}

	/**
	 * 剪切文件
	 * @param source 目标文件
	 * @param dest 目的文件
	 * @throws Exception
	 */
	private static void cutFile(File source, File dest) throws Exception {
		copyFile(source, dest);
		deleteFile(source);
	}// end copyFile

	/**
	 * 剪切文件夹
	 * @param source 目标文件夹
	 * @param dest 目的文件夹
	 * @throws Exception
	 */
	private static void cutDir(File source, File dest) throws Exception {
		copyDir(source, dest);
		deleteDir(source);
	}// end copyDict

	public static void fileCut(File source, File dest) throws Exception {
		if (source.equals(dest)) {
			return;
		}
		if (source.isDirectory() && dest.isDirectory()) {
			cutDir(source, dest);
		} else if (!source.isDirectory() && !dest.isDirectory()) {
			cutFile(source, dest);
		}
	}

	public static void fileCopy(File source, File dest) throws Exception {
		Log.i("fileCopy", "source is:" + source.getAbsolutePath());
		Log.i("fileCopy", "dest is:" + dest.getAbsolutePath());
		if (source.equals(dest)) {
			dest = new File(dest.getPath(), "Copy of " + dest.getName());
		}
		if (source.isDirectory() && dest.isDirectory()) {
			copyDir(source, dest);
		} else if (!source.isDirectory() && !dest.isDirectory()) {
			copyFile(source, dest);
		}
	}

	public static void fileDelete(File source) throws Exception {
		if (source.isDirectory()) {
			deleteDir(source);
		} else {
			deleteFile(source);
		}
	}

	public static void fileRename(File source, File newName) throws Exception {
		if (!source.renameTo(newName)) {
			throw new Exception();
		}
	}

	public static void newFolder(File folder) throws Exception {
		if (!folder.mkdir()) {
			throw new Exception();
		}
	}

	public static List<File> searchFile(String keyWord) {
		final List<File> matchFile = new ArrayList<File>();
		final File root = new File("/");
		final File[] files = root.listFiles();
		for (int i = 0; i < files.length; i++) {
			if (files[i].getName().contains(keyWord)) {
				matchFile.add(files[i]);
			}
			if (files[i].isDirectory()) {
				final List<File> result = searchFile(keyWord);
				for (int j = 0; i < result.size(); j++) {
					matchFile.add(result.get(i));
				}
			}
		}
		return matchFile;
	}

}
